package cn.webestar.scms.mybatisplus;

import cn.hutool.core.lang.Snowflake;
import cn.webestar.scms.mybatisplus.function.CustomizedSqlInjector;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author zgs
 */
@Slf4j
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnClass({RedisOperations.class, RedisTemplate.class})
@EnableConfigurationProperties(MybatisPlusProperties.class)
public class MybatisPlusAutoConfig {

    @Autowired
    private MybatisPlusProperties properties;

    @Bean
    @ConditionalOnMissingBean
    @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
    public Snowflake idGenerator() {
        log.info("[mybatis-plus-spring-boot-starter]:Init Snowflake");
        return new Snowflake();
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 3.4.0版本会自动对count中的join进行优化
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        //paginationInnerInterceptor.setDbType(DbType.POSTGRE_SQL);
        //paginationInnerInterceptor.setDialect(new PostgreDialect());
        // 设置请求的页面大于最大页后操作， true调回到首页，false 继续请求  默认false
        paginationInnerInterceptor.setOverflow(false);
        // 设置最大单页限制数量，默认 500 条，-1 不受限制
        paginationInnerInterceptor.setMaxLimit(500L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        log.info("[mybatis-plus-spring-boot-starter]:Init MybatisPlusInterceptor");
        return interceptor;
    }

    @Bean
    public CustomizedSqlInjector customizedSqlInjector() {
        return new CustomizedSqlInjector();
    }

    @Bean
    public IdentifierGenerator identifierGenerator() {
        return entity -> idGenerator().nextId();
    }

    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, ?> redisTemplate(RedisConnectionFactory factory) {
        ObjectMapper om = new ObjectMapper();
        // 支持 LocalDate、LocalDateTime的序列号
        om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
        om.registerModule(new JavaTimeModule());
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        RedisTemplate<String, ?> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om, Object.class);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        log.info("[mybatis-plus-spring-boot-starter]:Init RedisTemplate");
        return template;
    }

}
